/**
 *                            License
 * THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS
 * CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE").
 * THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW.
 * ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR
 * COPYRIGHT LAW IS PROHIBITED.
 *
 * BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND
 * AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE
 * MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED
 * HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
 *
 */

/*
package l1j.server.server;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.server.L1DatabaseFactory;
import l1j.server.server.utils.SQLUtil;

public class IdFactory {
	private static Logger _log = Logger.getLogger(IdFactory.class.getName());

	private int _curId;

	private Object _monitor = new Object();

	private static final int FIRST_ID = 0x10000000;

	private static IdFactory _instance = new IdFactory();

	private IdFactory() {
		loadState();
	}

	public static IdFactory getInstance() {
		return _instance;
	}

	public int nextId() {
		synchronized (_monitor) {
			return _curId++;
		}
	}

	private void loadState() {
		// 取得資料庫中最大的ID+1
		Connection con = null;
		PreparedStatement pstm = null;
		ResultSet rs = null;

		try {
			con = L1DatabaseFactory.getInstance().getConnection();
			pstm = con
					.prepareStatement("select max(id)+1 as nextid from (select id from character_items union all select id from character_teleport union all select id from character_warehouse union all select id from character_elf_warehouse union all select objid as id from characters union all select clan_id as id from clan_data union all select id from clan_warehouse union all select objid as id from pets) t");
			rs = pstm.executeQuery();

			int id = 0;
			if (rs.next()) {
				id = rs.getInt("nextid");
			}
			if (id < FIRST_ID) {
				id = FIRST_ID;
			}
			_curId = id;
		} catch (SQLException e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
		} finally {
			SQLUtil.close(rs);
			SQLUtil.close(pstm);
			SQLUtil.close(con);
		}
	}
}
 */

/**
 *                            License
 * THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS
 * CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE").
 * THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW.
 * ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR
 * COPYRIGHT LAW IS PROHIBITED.
 *
 * BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND
 * AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE
 * MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED
 * HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
 *
 */
package l1j.server.server;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.server.DatabaseFactory;
import l1j.server.server.utils.SQLUtil;

public class IdFactory {
	private static Logger _log = Logger.getLogger(IdFactory.class.getName());

	public static IdFactory getInstance() {
		return _instance;
	}

	private int _curId = 0;

	private int i = 0;

	private boolean isLoadState = false;

	private final Object _monitor = new Object();

	private static final int FIRST_ID = 0x80; // id從128開始

	private static IdFactory _instance = new IdFactory();

	private final ArrayList<Integer> idList = new ArrayList<Integer>();

	private IdFactory() {
		this.resetId();
		if (this.idList.size() > 1) { // 運行結果有兩個的時候，才能夠進行回收
			while (this.i + 1 < this.idList.size()) {
				if (this.idList.get(this.i + 1) - this.idList.get(this.i) > 1) {
					this._curId = this.idList.get(this.i) + 1;
					break;
				}
				++this.i;
			}
			if (this._curId > 0)
			{
				_log.info("目前對象使用回收ID: " + this._curId);
			} else
			{
				this.loadState();
				_log.info("目前對象使用新ID: " + this._curId);
			}
		} else
		{
			this.loadState();
			_log.info("目前對象使用新ID: " + this._curId);
		}
	}

	private void loadState() {
		if (this.idList.size() > 0) {
			this._curId = this.idList.get(this.idList.size() - 1) + 1;
			if (this._curId < FIRST_ID) {
				this._curId = FIRST_ID;
			}
		} else {
			this._curId = FIRST_ID;
		}
		this.isLoadState = true;
	}

	public int nextId() {
		synchronized (this._monitor) { // 鎖住newobject，防止同時另外一個對象產生
			if (this.isLoadState) {// 啟用新id後使用遞增
				return ++this._curId;
			}
			if (this._curId + 1 < this.idList.get(this.i + 1)) {
				++this._curId;
			} else {
				++this.i; // i值取下一位
				this._curId = 0; // _curId重置
				while (this.i + 1 < this.idList.size()) {
					if (this.idList.get(this.i + 1) - this.idList.get(this.i) > 1) {
						this._curId = this.idList.get(this.i) + 1;
						break;
					}
					++this.i;
				}
				if (this._curId <= 0) {
					this.loadState();
				}
			}
			return this._curId;
		}
	}
	//	private void loadState() {
	// 取得資料庫中最大的ID+1
	private void resetId() {
		Connection con = null;
		PreparedStatement pstm = null;
		ResultSet rs = null;

		try {
			con = DatabaseFactory.get().getConnection();
			pstm = con.prepareStatement("select id from (select id from character_items union all select id from character_teleport union all select id from character_warehouse union all select id from character_elf_warehouse union all select objid as id from characters union all select clan_id as id from clan_data union all select id from clan_warehouse union all select id from z_opqlo_autoshop union all select objid as id from pets) t order by id");
			rs = pstm.executeQuery();

			/*
			int id = 0;
			if (rs.next()) {
				id = rs.getInt("nextid");
			}
			if (id < FIRST_ID) {
				id = FIRST_ID;
			}
			_curId = id;
			 */
			while (rs.next()) {
				this.idList.add(rs.getInt("id"));
			}
		} catch (final SQLException e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
		} finally {
			SQLUtil.close(rs);
			SQLUtil.close(pstm);
			SQLUtil.close(con);
		}
	}
}

